/**
* Copyright 2017 Pivotal Software, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.metrics.instrument.scheduling;
import com.google.common.base.Functions;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.metrics.instrument.LongTaskTimer;
import org.springframework.metrics.instrument.MeterRegistry;
import org.springframework.metrics.instrument.Tags;
import org.springframework.metrics.instrument.Timer;
import org.springframework.metrics.annotation.Timed;
import org.springframework.metrics.instrument.internal.TimedUtils;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.stream.Collectors;
@Aspect
public class MetricsSchedulingAspect {
private static final Log logger = LogFactory.getLog(MetricsSchedulingAspect.class);
private final MeterRegistry registry;
public MetricsSchedulingAspect(MeterRegistry registry) {
this.registry = registry;
}
@Around("execution (@org.springframework.scheduling.annotation.Scheduled * *.*(..))")
public Object timeScheduledOperation(ProceedingJoinPoint pjp) throws Throwable {
Method method = ((MethodSignature) pjp.getSignature()).getMethod();
String signature = pjp.getSignature().toShortString();
if (method.getDeclaringClass().isInterface()) {
try {
method = pjp.getTarget().getClass().getDeclaredMethod(pjp.getSignature().getName(),
method.getParameterTypes());
} catch (final SecurityException | NoSuchMethodException e) {
logger.warn("Unable to perform metrics timing on " + signature, e);
return pjp.proceed();
}
}
Map<Boolean, Timed> timedAnnots = TimedUtils.findTimed(method)
.filter(t -> !t.value().isEmpty())
.collect(Collectors.toMap(Timed::longTask, Functions.identity()));
Timed shortTaskTimerAnnot = timedAnnots.get(false);
Timer shortTaskTimer = null;
if(shortTaskTimerAnnot != null)
shortTaskTimer = registry.timer(shortTaskTimerAnnot.value(), Tags.tagList(shortTaskTimerAnnot.extraTags()));
Timed longTaskTimerAnnot = timedAnnots.get(true);
LongTaskTimer longTaskTimer = null;
if(longTaskTimerAnnot != null)
longTaskTimer = registry.longTaskTimer(longTaskTimerAnnot.value(), Tags.tagList(longTaskTimerAnnot.extraTags()));
if(shortTaskTimer != null && longTaskTimer != null) {
final Timer finalTimer = shortTaskTimer;
return longTaskTimer.recordThrowable(() -> finalTimer.recordThrowable(pjp::proceed));
}
else if(shortTaskTimer != null) {
return shortTaskTimer.recordThrowable(pjp::proceed);
}
else if(longTaskTimer != null) {
return longTaskTimer.recordThrowable(pjp::proceed);
}
return pjp.proceed();
}
}